#ifndef  __PCB_H__
#define  __PCB_H__

#include  "semaphor.h"
#include  "thread.h"

/* 
 * Menja ponasanje delete_from_list funkcije
 *
 * Umesto da ostavlja Thread-u da brise PCB, to radi delete_from_list funkcija.
 * Potrebno za test sa PCB-ovima(pcb_test.cpp).
 */
//#define PCB_TEST
class Queue;

#define MAX_PROC 26
#define MAX_STACK 65536

class PCB {
    public:
        /** 
         * @brief Nova nit, jos nije stigla da inicijalizuje stek
         */
        static const int NEW;
        /** 
         * @brief Nit koja je spremna za izvrsavanje, ima stek.
         */
        static const int READY;
        /** 
         * @brief Nit je blokirana na nekoj sihronizacionoj primitivi, ili je
         * blokirana nad nekom niti(waitToComplete)
         */
        static const int BLOCKED;
        /** 
         * @brief Nit koja je zavrsila sa izvrsavanjem, moze se izbrisati iz
         * tabele niti(all_pcbs).
         */
        static const int FINISHED;
        /** 
         * @brief Dohvatanje niti na osnovu sistemskog ID
         * 
         * @param id
         * ID niti koja se trazi
         * 
         * @return 
         * Pokazivac na nit koja ima dati ID, ili NULL ako
         * takva nit ne postoji
         */
        static Thread* getThreadById(ID id);
        /** 
         * @brief Brise nit iz sistema
         *
         * Oslobadja prostor koji je bio rezervisan za stack i dinamicku
         * struktu waitQueue.
         */
         ~PCB();

        /** 
         * @brief Formira sve podatke niti
         * 
         * @param uid 
         * Moze se zadati od strane korisnike, ako se stavi
         * vrednost -1, onda ce sistem sam izabrati jedinstveni broj.
         *
         * @param priority
         * Za sada nedefinisan...
         *
         * @param stackSize 
         * Velicina korisnickog steka niti.
         *
         * @param timeSlice 
         * Vreme dodeljeno za izvrsavanje niti u sistemu.
         *
         * ID sistema sam stavio da bude uvek jednak korisnickom ID-u. Iako
         * pamtim ta dva identifikatora odvojeno, pa je kasnije moguce da se
         * oni razlikuju...
         *
         */
        PCB (Thread* myThread,
                UID _uid,
                Priority priority,
                StackSize stackSize,
                Time timeSlice);

        /** 
         * @brief Inicijalizuje stack niti na podrazumevane vrednosti
         *
         * Inicijalizacija stack-a se vrsi tako da pri povratku iz prekidne
         * rutine ona vrati u funkciju(wrapper) koja poziva run() metodu njene
         * niti.
         */
        void init_stack();

        /** 
         * @brief Pokazivac na roditeljsku nit
         */
        Thread*   my_thread;
        /** 
         * @brief Vreme izvrsavanja niti
         */
        Time      time_slice;
        /*************** 
         * SIHRONIZACIJA
         **************/
        /** 
         * @brief Vreme kojim je odredjeno koliko ce data nit da ceka na signal
         */
        Time      time_wait;
        /** 
         * @brief Povratna vrednost pri vracanju iz wait funkcije
         * 
         * Ovo je privremeno skladiste za vracanje prave vrednosti iz wait()
         * metode.
         */
        int       wait_return;
        /** 
         * @brief Semafor nad kojim je blokirana data nit
         * 
         * Ovaj podatak je potreban da bi se ocuvala konzistentnost semafora.
         */
        KernelSem* kern_sem_own;
        
        /** 
         * @brief Velicina stack-a niti
         *
         * Max: (64KB)
         */
        StackSize stack_size;
        /** 
         * @brief Korisnicki identifikator niti
         */
        UID       uid;
        /** 
         * @brief Sistemski identifikator niti
         */
        ID        id;
        /** 
         * @brief Niti koje cekaju da se ova nit zavrsi
         */
        Queue*     waitQueue;

        /** 
         * @brief Trenutno stanje niti.
         *
         * Detalje o mogucim vrednostima vidite u dokumentaciji za svako stanje
         */
        volatile int       state;
        /** 
         * @brief Pokazivac na stek niti
         */
        unsigned char*     p_sp;
        /** 
         * @brief Registar SP niti
         */
        unsigned           sp;
        /** 
         * @brief Registar SS niti
         */
        unsigned           ss;

        /** 
         * @brief Ovu promenljivu koristimo da vidimo koliko se izvrsavala data
         * nit, ili koliko je ukupno cekala nad semaforom.
         */
        volatile Time      time_passed;



        /** 
         * @brief Svi procesi u sistemu, ne validni unosi su NULL
         *
         * Skica liste
         * [*****#########{END_NULL}]
         * * predstavlja validne
         * # nevalidne unose
         *
	 * Lista nije uredjena ni po jednom kriterijumu element liste je
	 * pokazivac na PCB.
         * 
         * Zadnji clan je oznacen promenljivom PCB::last_index
         */
        static PCB*   all_pcbs[MAX_PROC + 1];
        /** 
         * @brief Index prvog elementa posle zadnjeg iskoriscenog polja
         */
        static int    last_index;
        /** 
         * @brief Promenljiva koju koristimo za generisanje jedinstvenih UID
         * identifikatora u sistemu.
         */
        static int    id_cnt;

        /** 
         * @brief dodaje element PCB u listu svih procesa
         * 
         * @param PCB* 
         */
        static void   add_to_list(PCB* );

        /** 
         * @brief brise PCB iz liste
         * 
         * @param PCB* 
         */
        static void  del_from_list(PCB* );

        /** 
         * @brief Ova funkcija na govori da li postoje neke niti osim starting
         * i idle.
         * 
         * @return 
         * Vraca vrednost 1(TRUE), ako ima drugih niti, ili 0(FALSE) ako ih nema.
         */
        static int   exist_other_thr();

        /** 
         * @brief Prolazi kroz sve procese, i za one koji su blokirani
         * proverava da li im je isteklo vreme cekanja
         * 
         * Predvidjeno je da se pokrece samo u Doxon::timer_int. Moze da se
         * poziva i iz drugih funkcija, ali samo pod uslovom da se nalazi
         * izmedju lock()/unlock() primitiva.
         */
        static void  refresh_blocked();

        /** 
         * @brief Vraca jedinstveni korisnicki identifikator na nivou sistema
         * 
         * @param _uid 
         * 
         * @return 
         */
        static UID    get_uniq_uid(UID _uid);

};
#endif  /*__PCB_H__*/
